
let {Matrix4} = require('../math');
let Transform = require('./Transform');
let {ShaderLib,ShaderName} = require('../shader');

let _vmMatrix = new Matrix4();
class Obj3D{

    /**
     *
     * @param obj {{
     *     mesh:MeshData,
     *     shaderName:string,
     *     texId:GLint|null,
     * }}
     */
    constructor(obj) {
        this._transform  = new Transform();

        let {mesh, shaderName} = obj;
        let shader = ShaderLib.getShader(shaderName);
        let gl = this._gl = ShaderLib._gl;
        this._prmitive = gl.TRIANGLES;

        this._renderFunc = null;

        switch (shaderName) {
            case ShaderName.POS:
            {
                let vao = gl.createVertexArrayOES();
                gl.bindVertexArrayOES(vao);
                let posVBO = gl.createBuffer();
                gl.bindBuffer(gl.ARRAY_BUFFER,posVBO);
                gl.bufferData(gl.ARRAY_BUFFER,mesh.positions,gl.STATIC_DRAW);
                gl.enableVertexAttribArray(shader.attribs['a_position']);
                gl.vertexAttribPointer(shader.attribs['a_position'],3,gl.FLOAT,false,0,0);
                let vertexSize = mesh.positions.length/3;
                this._renderFunc =  (camera) => {
                    gl.useProgram(shader.program);
                    _vmMatrix.multiplyMatrices(camera.getViewMatrix(),this._transform.getWorldMatrix());
                    shader.setMatrix4('projMatrix',camera.getProjMatrix());
                    shader.setMatrix4('vmMatrix',_vmMatrix);
                    gl.bindVertexArrayOES(vao);
                    gl.drawArrays(this._prmitive,0,vertexSize);
                };
            }
                break;
            case ShaderName.POS_1:
            {
                let vao = gl.createVertexArrayOES();
                gl.bindVertexArrayOES(vao);
                let posVBO = gl.createBuffer();
                gl.bindBuffer(gl.ARRAY_BUFFER,posVBO);
                gl.bufferData(gl.ARRAY_BUFFER,mesh.positions,gl.STATIC_DRAW);
                gl.enableVertexAttribArray(shader.attribs['a_position']);
                gl.vertexAttribPointer(shader.attribs['a_position'],3,gl.FLOAT,false,0,0);

                let ibo = gl.createBuffer();
                gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,ibo);
                gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,mesh.indices,gl.STATIC_DRAW);
                let vertexSize = mesh.indices.length;

                this._renderFunc =  (camera) => {
                    gl.useProgram(shader.program);
                    _vmMatrix.multiplyMatrices(camera.getViewMatrix(),this._transform.getWorldMatrix());
                    shader.setMatrix4('projMatrix',camera.getProjMatrix());
                    shader.setMatrix4('vmMatrix',_vmMatrix);
                    gl.bindVertexArrayOES(vao);
                    gl.drawElements(this._prmitive,vertexSize,gl.UNSIGNED_SHORT,0);
                };
            }
                break;
            case ShaderName.POS_UV:
            {
                let vao = gl.createVertexArrayOES();
                gl.bindVertexArrayOES(vao);
                let posVBO = gl.createBuffer();
                gl.bindBuffer(gl.ARRAY_BUFFER,posVBO);
                gl.bufferData(gl.ARRAY_BUFFER,mesh.positions,gl.STATIC_DRAW);
                gl.enableVertexAttribArray(shader.attribs['a_position']);
                gl.vertexAttribPointer(shader.attribs['a_position'],3,gl.FLOAT,false,0,0);

                let ibo = gl.createBuffer();
                gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,ibo);
                gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,mesh.indices,gl.STATIC_DRAW);
                let vertexSize = mesh.indices.length;

                let uvVBO = gl.createBuffer();
                gl.bindBuffer(gl.ARRAY_BUFFER,uvVBO);
                gl.bufferData(gl.ARRAY_BUFFER,mesh.texCoords,gl.STATIC_DRAW);
                gl.enableVertexAttribArray(shader.attribs['a_texCoord']);
                gl.vertexAttribPointer(shader.attribs['a_texCoord'],2,gl.FLOAT,false,0,0);

                let texId = obj.texId;
                this._renderFunc =  (camera) => {
                    gl.useProgram(shader.program);
                    _vmMatrix.multiplyMatrices(camera.getViewMatrix(),this._transform.getWorldMatrix());
                    shader.setMatrix4('projMatrix',camera.getProjMatrix());
                    shader.setMatrix4('vmMatrix',_vmMatrix);
                    shader.setUniform1i('u_sampler',0);
                    gl.activeTexture(gl.TEXTURE0);
                    gl.bindTexture(gl.TEXTURE_2D,texId);
                    gl.bindVertexArrayOES(vao);
                    gl.drawElements(this._prmitive,vertexSize,gl.UNSIGNED_SHORT,0);
                };
            }
                break;
            case ShaderName.POS_UV_NORMAL:
                // TODO:
                break;
        }

    }

    getTransform(){
        return this._transform;
    }

    render(camera){
        if (this._renderFunc){
            this._renderFunc(camera);
        }
    }
}

module.exports = Obj3D;
